/* Copyright (c) 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.orkut.client.api.samples.greetings.server.login;

import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.authn.oauth.OAuthHelper;
import com.google.gdata.client.authn.oauth.OAuthParameters;
import com.google.inject.Inject;
import com.google.orkut.client.api.samples.greetings.server.Cookies;
import com.google.orkut.client.api.samples.greetings.server.db.GreetingsDb;
import com.google.orkut.client.api.samples.greetings.shared.CommonConstants;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Random;

/**
 * An auth service which handles login.
 *
 * @author Shishir Birmiwal
 */
public class OrkutAuthService {

  private static final String REDIRECT_TO = "/fotoscrapr.jsp";
  private static final String COOKIE_NAME = "oats";
  private final OAuthHelper oauthHelper;
  private final OAuthParameters oauthParams;
  private final GreetingsDb db;
  private final Random random;

  @Inject
  public OrkutAuthService(
      OAuthHelper oauthHelper,
      OAuthParameters oauthParams,
      GreetingsDb db,
      Random random) {
    this.oauthHelper = oauthHelper;
    this.oauthParams = oauthParams;
    this.db = db;
    this.random = random;
  }

  public void doRedirectToLogin(HttpServletRequest req, HttpServletResponse resp)
  throws IOException {
    String loginCookie = Cookies.getCookieValueFor(req, CommonConstants.COOKIE);
    if (loginCookie != null) {
      // already logged in
      resp.sendRedirect(getContinueUrl());
      return;
    }

    oauthParams.setOAuthCallback(req.getRequestURL().toString());
    try {
      oauthHelper.getUnauthorizedRequestToken(oauthParams);
    } catch (OAuthException e) {
      showError(req, resp);
      return;
    }

    Cookie cookie = new Cookie(COOKIE_NAME, oauthParams.getOAuthTokenSecret());
    resp.addCookie(cookie);

    String approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParams);
    resp.sendRedirect(approvalPageUrl);
  }

  private void showError(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    clearLoginCookie(resp);
    resp.sendError(500, "Internal Server error while handling request. Please try again!");
  }

  public void processLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // get the oaauth token secret from the cookie
    String oauthTokenSecret = getOauthTokenSecretFromCookie(req);
    // no cookie found with auth token
    if (oauthTokenSecret == null) {
      doRedirectToLogin(req, resp);
      return;
    }

    oauthParams.setOAuthTokenSecret(oauthTokenSecret);
    oauthHelper.getOAuthParametersFromCallback(req.getQueryString(), oauthParams);

    String accessToken;
    try {
      accessToken = oauthHelper.getAccessToken(oauthParams);
    } catch (OAuthException e) {
      doRedirectToLogin(req, resp);
      return;
    }

    String accessTokenSecret = oauthParams.getOAuthTokenSecret();
    String sessionToken = getRandomKey();
    db.storeCredentials(sessionToken, accessToken, accessTokenSecret);
    clearLoginCookie(resp);
    setSessionCookie(resp, sessionToken);
    resp.sendRedirect(getContinueUrl());
  }

  private void setSessionCookie(HttpServletResponse resp, String sessionToken) {
    Cookie cookie = new Cookie(CommonConstants.COOKIE, sessionToken);
    resp.addCookie(cookie);
    cookie.setMaxAge(3600 * 24 * 14);
  }

  private String getContinueUrl() {
    return REDIRECT_TO;
  }

  private String getRandomKey() {
    return random.nextLong() + ":" + random.nextLong() + ":" + random.nextLong();
  }

  private void clearLoginCookie(HttpServletResponse resp) {
    Cookie cookie = new Cookie(COOKIE_NAME, "");
    cookie.setMaxAge(0);
    resp.addCookie(cookie);
  }

  private String getOauthTokenSecretFromCookie(HttpServletRequest req) {
    Cookie[] cookies = req.getCookies();
    for (Cookie cookie : cookies) {
      if (cookie.getName().equals(COOKIE_NAME)) {
        return cookie.getValue();
      }
    }
    return null;
  }
}
